import utils from '../utils'
import Geom from '../geom'
import {ArcCollection} from '../paths'
import Dataset from './index.js'

// Don't modify input layers (mergeDatasets() updates arc ids in-place)
function mergeDatasetsForExport(arr) {
  // copy layers but not arcs, which get copied in mergeDatasets()
  const copy = arr.map((dataset) => {
    return utils.defaults({
      layers: dataset.layers.map(Dataset.copyLayerShapes)
    }, dataset)
  })
  return mergeDatasets(copy)
}
// Combine multiple datasets into one using concatenation
// (any shared topology is ignored)
function mergeDatasets(arr) {
  const arcSources = []
  let arcCount = 0
  const mergedLayers = []
  const mergedInfo = {}

  // Error if incompatible CRS
  requireDatasetsHaveCompatibleCRS(arr)

  arr.forEach((dataset) => {
    const n = dataset.arcs ? dataset.arcs.size() : 0
    if (n > 0) {
      arcSources.push(dataset.arcs)
    }

    mergeDatasetInfo(mergedInfo, dataset)
    dataset.layers.forEach((lyr) => {
      if (lyr.geometry_type == 'polygon' || lyr.geometry_type == 'polyline') {
        utils.forEachArcId(lyr.shapes, function(id) {
          return id < 0 ? id - arcCount : id + arcCount
        })
      }
      mergedLayers.push(lyr)
    })
    arcCount += n
  })

  const mergedArcs = mergeArcs(arcSources)
  if (mergedArcs.size() != arcCount) {
    utils.error("[mergeDatasets()] Arc indexing error")
  }

  return {
    info: mergedInfo,
    arcs: mergedArcs,
    layers: mergedLayers
  }
}
function requireDatasetsHaveCompatibleCRS(arr) {
  arr.reduce((memo, dataset) => {
    const P = Geom.getDatasetCRS(dataset)
    if (memo && P) {
      if (Geom.isLatLngCRS(memo) != Geom.isLatLngCRS(P)) {
        // stop("Unable to combine projected and unprojected datasets")
        utils.error('Unable to combine projected and unprojected datasets')
      }
    }
    return P || memo
  }, null)
}
function mergeDatasetInfo(merged, dataset) {
  const info = dataset.info || {}
  merged.input_files = utils.uniq((merged.input_files || []).concat(info.input_files || []))
  merged.input_formats = utils.uniq((merged.input_formats || []).concat(info.input_formats || []))
  // merge other info properties (e.g. input_geojson_crs, input_delimiter, prj, crs)
  utils.defaults(merged, info)
}
function mergeArcs(arr) {
  const dataArr = arr.map((arcs) => {
    if (arcs.getRetainedInterval() > 0) {
      // verbose("Baking-in simplification setting.")
      arcs.flatten()
    }
    return arcs.getVertexData()
  })
  const xx = mergeArrays(utils.pluck(dataArr, 'xx'), Float64Array)
  const yy = mergeArrays(utils.pluck(dataArr, 'yy'), Float64Array)
  const nn = mergeArrays(utils.pluck(dataArr, 'nn'), Int32Array)

  return new ArcCollection(nn, xx, yy)
}
function countElements(arrays) {
  return arrays.reduce((memo, arr) => {
    return memo + (arr.length || 0)
  }, 0)
}
function mergeArrays(arrays, TypedArr) {
  const size = countElements(arrays)
  const Arr = TypedArr || Array
  const merged = new Arr(size)
  let offs = 0
  arrays.forEach((src) => {
    const n = src.length
    for (let i = 0; i<n; i++) {
      merged[i + offs] = src[i]
    }
    offs += n
  })
  return merged
}
export default {
  mergeDatasetsForExport,
}